package se.vgregion.icc;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.apache.activemq.util.ByteArrayInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import se.riv.itintegration.monitoring.pingforconfigurationresponder.v1.ConfigurationType;
import se.riv.itintegration.monitoring.pingforconfigurationresponder.v1.PingForConfigurationResponseType;
import se.riv.itintegration.monitoring.pingforconfigurationresponder.v1.PingForConfigurationType;

/***
 * Provides help methods to read and modify responses.
 *
 * @author ricra2 & andan40
 * @see {@link se.riv.itintegration.monitoring.pingforconfigurationresponder.v1.PingForConfigurationResponseType}<br/>
 */
public final class ResponseHelper {

    /** Class logger. */
    private static final Logger LOG = LoggerFactory.getLogger(ResponseHelper.class);

    private static final String GET_URL_VALUE_XPATH_EXPRESSION = "//configuration[name='URL']/value/text()";

    private ResponseHelper() {
    }

    /**
     * Adds a configuration property to the PingForConfigurationResponse.
     * 
     * @param response the response object on which to add configuration information.
     * @param name the name of the configuration property to add.
     * @param value the value of the configuration property to add.
     */
    public static void addConfiguration(PingForConfigurationResponseType response, String name, String value) {
        ConfigurationType conf = new ConfigurationType();
        conf.setName(name);
        conf.setValue(value);

        response.getConfiguration().add(conf);
        LOG.debug("Added information to configuration tag: name= {}, value= {}", name, value);
    }

    /***
     * Adds the url's from the response xml to PingForConfigurationType's logicalAddress so that
     * you know what you already have pinged.
     * 
     * @param responseXml the response xml that you want to get the url's from
     * @param parameters the PingForConfigurationType that you want to add 
     */
    public static void addAlreadyPingedToResponse(String responseXml, PingForConfigurationType parameters) {

        LOG.debug("Tries to add already pinged dependency to list");

        responseXml = PingForConfigurationUtils.restoreXmlTags(responseXml);
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(new ByteArrayInputStream(responseXml.getBytes()));
            doc.getDocumentElement().normalize();

            XPathFactory xpathFactory = XPathFactory.newInstance();
            XPath xpath = xpathFactory.newXPath();
            XPathExpression expression = xpath.compile(GET_URL_VALUE_XPATH_EXPRESSION);

            NodeList nodes = (NodeList) expression.evaluate(doc, XPathConstants.NODESET);

            for (int i = 0; i < nodes.getLength(); i++) {
                String url = nodes.item(i).getNodeValue();
                if (!parameters.getLogicalAddress().contains(url)) {
                    parameters.setLogicalAddress(parameters.getLogicalAddress() + "|" + url);
                }
            }
            LOG.debug("Everything went ok with adding the already pinged dependency");
        } catch (Exception e) {
            LOG.debug("Something went wrong with adding the already pinged dependency");
            e.printStackTrace();
        }
    }

    /***
     * Checks if the logical address is already pinged.
     * 
     * @param parameters the PingForConfigurationType that contains a String with already pinged dependencies
     * @param logicalAddress the logical address that you what to check if it's already pinged
     * @return true if address is already pinged, else false.
     */
    public static boolean isAlreadyPinged(PingForConfigurationType parameters, String logicalAddress) {
        boolean isAlreadyPinged = false;
        if (parameters != null && logicalAddress != null) {
            String alreadyPingedAddresses = parameters.getLogicalAddress();
            if (alreadyPingedAddresses != null) {
                String[] alreadyPinged = alreadyPingedAddresses.split("\\|");
                isAlreadyPinged = PingForConfigurationUtils.doesObjectExistInArray(logicalAddress, alreadyPinged);
                if (isAlreadyPinged) {
                    LOG.debug("{} is already pinged", logicalAddress);
                }
            }
        }
        return isAlreadyPinged;
    }
}
